#ifndef PROCESS_MANAGEMENT_H
#define PROCESS_MANAGEMENT_H

#define STACK_SIZE 0x1000

#include "max_priority.h"
#include "system_id.h"
#include "types.h"
#include "pcb.h"
#include "scheduler.h"
#include "delay.h"
#include "user_programs.h"
#include "uart.h"
#include "process_supervision.h"
#include "dynamic_memory.h"
#include "linked_list.h"
#include "pcb_list.h"
#include "api.h"

/* function declarations */

/* initializes the processes list */
void initialize_processes_list();

/* creates a new process (with priority as priority level) by allocating a PCB to it and returns its pid. Returns either OUT_OF_MEMORY, WRONG_PRIORITY or UNKNOWN_PROGRAM in case of failure. This process executes the program named program_name. reschedule indicates whether a check has to be made for scheduling or not.  */
int32_t create_process(uint32_t priority, char* program_name, int32_t parent,int32_t parameters[4], int reschedule);

/* removes the PCB of the process pid. The function also passes the return value of the removed process to its parent (if it is waiting for). If the parent is not waiting for the termination of its child, the latter becomes a zombie whose PCB will only be deleted when:
   - the parent finally reads the return value
   - the parent terminates
*/
int32_t remove_process(int32_t pid, int32_t return_value);

/* removes the PCB pcb. The function also passes the return value of the removed process to its parent (if it is waiting for). If the parent is not waiting for the termination of its child, the latter becomes a zombie whose PCB will only be deleted when:
   - the parent finally reads the return value
   - the parent terminates
*/
int32_t remove_process_pcb(PCB* pcb, int32_t return_value);

/* frees PCB and its PID */
int32_t delete_pcb(PCB* pcb);

/* looks for pcb's children and changes their parents to SYSTEM_ID. Returns SUCCESS or FAILURE. */
int32_t adopt_children(PCB* pcb);

/* passes return_value of a process to pcb's parent if it is waiting for it. Otherwise, pcb becomes a zombie */
int32_t pass_return_value(PCB* pcb, int32_t return_value);

/* returns a pointer to the PCB with pid as pid */
PCB* get_process_by_pid(int32_t pid);

/* returns an array containing all the pid in the system and their number in length */
int32_t* get_all_pid(int32_t* length, int32_t owner);

/* changes the priority of the process pid */
int32_t change_priority(int32_t pid, int32_t priority);

/* blocks the process pid. It is only possible to block a process ready or running (blocking a delayed process would not make much sense).
Returns SUCCESS in case of successful blocking of the process, FAILURE otherwise */
int32_t block(int32_t pid);

/* blocks the process pointed by target. It is only possible to block a process ready, running or delayed. A delayed process does not resume its waiting when waking up. */
int32_t block_pcb(PCB* target);

/* wakes the process pid up.
   Returns SUCCESS in case of success, FAILURE otherwise.
*/
int32_t wake_up(int32_t pid);

/* wakes the process pointed by target up.
   Returns SUCCESS in case of success, FAILURE otherwise.
*/
int32_t wake_up_pcb(PCB* target);

/* delays the process pid by n ms.
   Returns SUCCESS if the process was sucessfully delayed, FAILURE otherwise.
*/
int32_t delay(int32_t pid, uint32_t n);

/* delays the process pointed by target during n ms.
   Returns SUCCESS if the process was sucessfully delayed, FAILURE otherwise. */
int32_t delay_pcb(PCB* target, uint32_t n);

/* Returns the priority of the process pid or FAILURE if it doesn't exist */
int32_t get_priority(int32_t pid);

/* Returns the program name of the program executed by pid or NULL if an error occurs. */
char* get_program(int32_t pid, int32_t owner);

/* returns the state of the process pid or FAILURE in case of failure */
int32_t get_state(int32_t pid);

/* returns the parent's pid of pid or FAILURE in case of failure */
int32_t get_parent(int32_t pid);

/* checks if the process pid has terminated. It it has, its return value is copied in status and the process is deleted. Otherwise, the caller is blocked until such an event occurs. Returns SUCCESS if no error happened (being blocked is NOT an error) or FAILURE otherwise. */
int32_t wait(int32_t pid, int32_t* status);


#endif
